package scene

import (
	"sync"

	"github.com/hwcer/cosgo/utils"
)

// Layer 场景层，负责管理特定层中的实体和AOI计算
// 作为Scene的多重镜像，Layer拥有自己的网格系统，负责具体的AOI管理

type Layer struct {
	id         int64      // 层ID
	scene      *Scene     // 场景指针
	gridWidth  int        // 网格列数
	gridHeight int        // 网格行数
	grids      [][]*Grid  // 二维网格系统，存储所有实体
	gridsLock  sync.Mutex // 网格锁
}

func NewLayer(id int64, scene *Scene) *Layer {
	l := &Layer{
		id:    id,
		scene: scene,
	}
	l.initGridSystem()
	return l
}

func (l *Layer) GetNearGrids(x, y float64, radius float64) (r []*Grid) {
	// 获取指定位置所在的网格索引并计算需要检查的网格范围
	gridX, gridY := l.getGridIndex(x, y)
	gridRadius := int(radius/l.scene.gridSize) + 1
	minX := utils.Max(0, gridX-gridRadius)
	maxX := utils.Min(l.gridWidth-1, gridX+gridRadius)
	minY := utils.Max(0, gridY-gridRadius)
	maxY := utils.Min(l.gridHeight-1, gridY+gridRadius)
	// 检查周围网格中的实体
	for i := minX; i <= maxX; i++ {
		for j := minY; j <= maxY; j++ {
			// 从每个网格获取符合条件的实体
			if grid := l.grids[i][j]; grid != nil {
				r = append(r, grid)
			}
		}
	}
	return r
}

// GetEntities 获取指定位置附近的指定类型实体
func (l *Layer) GetEntities(x, y float64, radius float64, entityType EntityType) []Entity {
	var entities []Entity
	for _, grid := range l.GetNearGrids(x, y, radius) {
		entities = append(entities, grid.GetEntities(x, y, radius, entityType)...)
	}
	return entities
}

// GetNearEntities 获取指定位置附近的指定类型实体
func (l *Layer) GetNearEntities(p Entity, radius float64, entityType EntityType) []Entity {
	var entities []Entity
	for _, grid := range l.GetNearGrids(p.GetX(), p.GetY(), radius) {
		entities = append(entities, grid.GetNearEntities(p, radius, entityType)...)
	}
	return entities
}

// GetNearPlayers 获取指定位置附近的玩家实体
func (l *Layer) GetNearPlayers(p Entity, radius float64) []Entity {
	return l.GetNearEntities(p, radius, EntityTypePlayer)
}

// Update 更新层的AOI信息
func (l *Layer) Update() {
	for i := range l.grids {
		for j := range l.grids[i] {
			grid := l.grids[i][j]
			grid.Update()
		}
	}
}

// Count 获取层中的实体总数
func (l *Layer) Count(et EntityType) int {
	count := 0
	// 计算所有网格中的实体数量
	if l.grids != nil {
		for i := range l.grids {
			for j := range l.grids[i] {
				grid := l.grids[i][j]
				count += grid.Count(et)
			}
		}
	}
	return count
}

// GetPlayerCount 获取层的当前玩家数量
func (l *Layer) GetPlayerCount() int {
	return l.Count(EntityTypePlayer)
}

// CanAddPlayer 检查层是否可以添加玩家
func (l *Layer) CanAddPlayer() bool {
	if l.scene.maxPlayers <= 0 {
		return true
	}
	c := l.GetPlayerCount()

	return c < l.scene.maxPlayers
}

// InitGridSystem 初始化层的网格系统
// 使用场景中的宽度、高度和网格大小初始化网格系统
func (l *Layer) initGridSystem() {
	// 计算网格数量
	if l.scene.enableAOI {
		l.gridWidth = int(l.scene.width/l.scene.gridSize) + 1
		l.gridHeight = int(l.scene.height/l.scene.gridSize) + 1
	} else {
		// 非AOI场景，网格系统设为1x1
		l.gridWidth = 1
		l.gridHeight = 1
	}
	index := int(0)
	// 初始化二维网格系统
	l.grids = make([][]*Grid, l.gridWidth)
	for i := range l.grids {
		l.grids[i] = make([]*Grid, l.gridHeight)
		for j := range l.grids[i] {
			index++
			l.grids[i][j] = NewGrid(index)
		}
	}
}

// GetScene 获取场景
func (l *Layer) GetScene() *Scene {
	return l.scene
}

// GetID 获取层ID
func (l *Layer) GetID() int64 {
	return l.id
}

// getGridIndex 计算实体在层网格系统中的坐标索引
func (l *Layer) getGridIndex(x, y float64) (int, int) {
	if !l.scene.enableAOI {
		// 非AOI场景，所有实体都在同一个网格中
		return 0, 0
	}

	gridX := int(x / l.scene.gridSize)
	gridY := int(y / l.scene.gridSize)

	// 确保在网格范围内
	gridX = utils.Max(0, utils.Min(gridX, l.gridWidth-1))
	gridY = utils.Max(0, utils.Min(gridY, l.gridHeight-1))

	return gridX, gridY
}

func (l *Layer) getGrid(x, y float64) *Grid {
	gridX, gridY := l.getGridIndex(x, y)
	if l.grids != nil {
		return l.grids[gridX][gridY]
	}
	return nil
}

// Add 添加实体到层
func (l *Layer) Add(entity Entity, x, y float64) bool {
	l.gridsLock.Lock()
	defer l.gridsLock.Unlock()
	grid := l.getGrid(x, y)
	if grid == nil {
		return false
	}
	// 设置实体的层ID
	entity.SetLayer(l)
	// 添加实体到网格系统
	grid.Add(entity)

	return true
}

// Remove 从层中移除实体
func (l *Layer) Remove(entity Entity, x, y float64) bool {
	l.gridsLock.Lock()
	defer l.gridsLock.Unlock()
	entity.SetLayer(nil)
	grid := l.getGrid(x, y)
	if grid == nil {
		return false
	}
	return grid.Remove(entity)
}

// Move 移动实体在层中的位置
// 更新实体的位置 由实体自身维护
func (l *Layer) Move(entity Entity, newX, newY float64) bool {
	// 计算实体当前和新位置所在的网格索引
	newGrid := l.getGrid(newX, newY)
	if newGrid == nil {
		return false //目标网格不存在
	}
	oldGrid := l.getGrid(entity.GetX(), entity.GetY())
	if oldGrid != nil && oldGrid.id == newGrid.id {
		return true
	}
	// 如果网格发生变化，更新实体所在的网格
	l.gridsLock.Lock()
	defer l.gridsLock.Unlock()
	newGrid.Add(entity)
	if oldGrid != nil {
		oldGrid.Remove(entity)
	}
	return true
}
